﻿/*  2008 R2 Object Explorer support.
 * see this blog
   http://blog.sqlblog.com/blogs/jonathan_kehayias/archive/2009/08/22/sql-2008-r2-breaks-ssms-addins.aspx
 you used to be able to hook up to the object explorer but now it just doesnt want to work
 * every interface or code snippet that is suggested no longer works as it either doesnt exist
 * or it is null, so to try again later add these references and uncomment the GetObjectExplorer method
 
     <Reference Include="Microsoft.SqlServer.SqlTools.VSIntegration">
      <HintPath>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.SqlServer.SqlTools.VSIntegration.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.VisualStudio.OLE.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.OLE.Interop.dll</HintPath>
    </Reference>
    <Reference Include="ObjectExplorer">
      <HintPath>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\ObjectExplorer.dll</HintPath>
    </Reference>
    <Reference Include="SqlWorkbench.Interfaces">
      <HintPath>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\SqlWorkbench.Interfaces.dll</HintPath>
    </Reference>
 * 
 // trying to get this to work only reason its in here is to use IObjectExplorer which doesnt work anymore since R2 so stuck
using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer;
using Microsoft.SqlServer.Management.UI.VSIntegration;
 
OR: PASTE This in PyPad
 * 
 import clr
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.SqlServer.SqlTools.VSIntegration.dll")
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.OLE.Interop.dll");
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\ObjectExplorer.dll")
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\SqlWorkbench.Interfaces.dll")

from Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer import *
from Microsoft.SqlServer.Management.UI.VSIntegration import *
  
 * and waste some time and then some more time
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using ACSR.SqlServer.AddIn.Core.Interface;
using ACSR.SqlServer.AddIn.Core.Interfaces;
using EnvDTE;
using EnvDTE80;
using Extensibility;


namespace ACSR.SqlServer.AddIn.Core.Controllers
{
    public class AddInController : IAddInController
    {

        [DllImport("user32.dll")]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        public static string MessageTypeToString(MessageType msgType)
        {
            switch (msgType)
            {
                case MessageType.Message:
                    return "Message";
                case MessageType.Warning:
                    return "Warning";
                case MessageType.Error:
                    return "Error";
                default:
                    return "Unknown";
            }
        }

        private DTE2 _applicationObject;
        private EnvDTE.AddIn _addInInstance;

        public EnvDTE.AddIn AddInInstance
        {
            get
            {
                return _addInInstance;
            }
        }

        public DTE2 ApplicationObject
        {
            get
            {
                return _applicationObject;
            }
        }

        CommandEvents _CommandEvents;

        public CommandEvents CommandEvents
        {
            get
            {
                return _CommandEvents;
            }
        }

        public event _dispCommandEvents_BeforeExecuteEventHandler OnBeforeExecute;
        public event _dispCommandEvents_AfterExecuteEventHandler OnAfterExecute;
        public event AddInMessageEvent OnMessage;
        public event AddInMessageEvent OnWarning;
        public event AddInMessageEvent OnError;

        protected string WorkingDirectory
        {
            get
            {
                return _workingDirectory;
            }
        }

        protected WindowManager WindowManager
        {
            get
            {
                return this._WindowManager;
            }
        }


        private Dictionary<string, dynamic> _commands;
        AddInContext _AddInContext;
        public void Initialize(AddInContext addinCtx, WindowManager windowManager)
        {
            _AddInContext = addinCtx;


            _CommandEvents = _applicationObject.Events.get_CommandEvents("{52692960-56BC-4989-B5D3-94C47A513E8D}", 1);
            _CommandEvents.AfterExecute += new _dispCommandEvents_AfterExecuteEventHandler(_CommandEvents_AfterExecute);
            _CommandEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(_CommandEvents_BeforeExecute);
            this._WindowManager = windowManager;
            _commands = new Dictionary<string, dynamic>();
        }

        public string CommonUIAssemblyLocation { get; set; }

        public void LockAround(object lockObject, Action<object> callback, object arg)
        {
            lock (lockObject)
            {
                callback(arg);
            }
        }


        public dynamic AddCommand(dynamic Bar, string name, string text, string toolTip, int imageIndex)
        {
            try
            {
                RemoveCommands(name);
                var cmd = AddNamedCommand(name, text, toolTip, 13);
                cmd.AddControl(Bar, 1);
                return cmd;
            }
            catch (Exception e)
            {
                LogError("Error AddInController.AddCommand: " + e.Message);
                throw;
            }
        }


        public dynamic AddNamedCommand(string name, string buttonText, string toolTip, int ImageId)
        {
            try
            {
                object[] contextGUIDS = new object[] { };
                int commandStatus = (int)vsCommandStatus.vsCommandStatusSupported +
                    (int)vsCommandStatus.vsCommandStatusEnabled;
                int commandStyle = (int)vsCommandStyle.vsCommandStylePictAndText;

                dynamic commands = _addInInstance.DTE.Commands;
                dynamic cmdResult = commands.AddNamedCommand2(_addInInstance, name,
                    buttonText, toolTip, true, ImageId,
                    ref contextGUIDS,
                    commandStatus,
                    commandStyle,
                    vsCommandControlType.vsCommandControlTypeButton);
                _commands[name] = cmdResult;

                return cmdResult;
            }
            catch (Exception x)
            {
                LogError("AddNamedCommand() Error: " + x.Message);
                return null;
            }
        }

        private List<Command> FindCommands(string commandName)
        {
            try
            {
                var commandItems = new List<Command>();

                foreach (Command cmd in _addInInstance.DTE.Commands)
                {
                    if (cmd.Name.ToString().Contains(commandName))
                    {
                        commandItems.Add(cmd);
                    }
                }
                return commandItems;
            }
            catch (Exception e)
            {
                LogError("Error AddInController.FindCommands: " + e.Message);
                throw;
            }
        }

        private void RemoveCommands(string commandName)
        {
            try
            {
                var commandItems = FindCommands(commandName);
                foreach (Command cmd in commandItems)
                {
                    try
                    {
                        LogMessage("deleting:" + cmd.Name);
                        cmd.Delete();
                    }
                    catch (Exception e)
                    {
                        LogError("Error AddInController.RemoveCommands.Delete: " + e.Message);
                        //throw;
                    }
                }
            }
            catch (Exception e)
            {
                LogError("Error AddInController.RemoveCommands: " + e.Message);
                throw;
            }
        }
        private dynamic _menuCommandBar = null;

        private dynamic GetCommandBars()
        {
            return _addInInstance.DTE.CommandBars;
        }

        private dynamic GetMenuCommandBar()
        {
            if (_menuCommandBar == null)
            {
                _menuCommandBar = GetCommandBars()["MenuBar"];
            }
            if (_menuCommandBar == null)
                throw new Exception("Menu bar is null");


            return _menuCommandBar;
        }

        private List<dynamic> FindCommandBarControls(dynamic menu, string commandBarName)
        {
            var menuItems = new List<dynamic>();
            foreach (var control in menu.CommandBar.Controls)
            {
                if (control.Caption.ToString().Contains(commandBarName))
                {
                    menuItems.Add(control);
                }
            }
            return menuItems;
        }

        private void RemoveCommandBarControls(dynamic menu, string commandBarName)
        {
            foreach (var control in FindCommandBarControls(menu, commandBarName))
            {
                control.Delete();
            }
        }

        private Commands GetCommands()
        {
            return _addInInstance.DTE.Commands;
        }

        private dynamic AddCommandBar(dynamic menu, string name)
        {
            return GetCommands().AddCommandBar(name,
                    vsCommandBarType.vsCommandBarTypeMenu, menu.CommandBar);
        }

        private dynamic ReAddCommandBar(dynamic menu, string name)
        {
            RemoveCommandBarControls(menu, name);
            return AddCommandBar(menu, name);
        }

        private dynamic GetToolsMenuControl()
        {
            var tools = GetMenuCommandBar().Controls["Tools"];
            if (tools == null)
                throw new Exception("tools is null");
            return tools;
        }

        protected dynamic CreateCommandBar(string menuName)
        {
            try
            {
                return ReAddCommandBar(GetToolsMenuControl(), menuName);
            }
            catch (Exception e)
            {
                LogError("Error AddInController.CreateCommandBar: " + e.Message);
                throw;
            }
        }




        protected virtual void InternalCommandEvents_AfterExecute(string Guid, int ID, object CustomIn, object CustomOut)
        {

        }

        protected virtual void InternalCommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
        {

        }

        void _CommandEvents_AfterExecute(string Guid, int ID, object CustomIn, object CustomOut)
        {

            InternalCommandEvents_AfterExecute(Guid, ID, CustomIn, CustomOut);
        }

        void _CommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
        {
            InternalCommandEvents_BeforeExecute(Guid, ID, CustomIn, CustomOut, ref CancelDefault);
        }


        IToolWindowContext _logWindow = null;

        dynamic _logWindowControl = null;
        string _workingDirectory;
        private string _uiDLL;
        public string UIDll
        {
            get
            {
                return _uiDLL;
            }
        }



        public bool IsTextWindow(Window window)
        {
            return (window != null && window.Selection != null && (window.Caption != "SQL Navigator"));
        }






        public void InternalLogMessage(string message, MessageType messageType)
        {
            LogMessageToFile(message, messageType);
            LogMessageToWindow(message, messageType);
        }

        public void LogWarning(string warning)
        {
            if (OnWarning != null)
            {
                OnWarning(this, warning, MessageType.Message);
            }
            InternalLogMessage(warning, MessageType.Warning);
        }

        public void LogMessage(string message)
        {
            if (OnMessage != null)
            {
                OnMessage(this, message, MessageType.Message);
            }
            InternalLogMessage(message, MessageType.Message);
        }

        public void LogError(string error)
        {
            if (OnError != null)
            {
                OnError(this, error, MessageType.Message);
            }
            LogMessageToFile(error, MessageType.Error);
            if (LogMessageToWindow(error, MessageType.Error))
            {
                return;
            }
            MessageBox.Show(error);
        }

        string FormatMessage(string message, MessageType messageType)
        {
            return string.Format("[{0:HH:MM:ss}][{1}]: {2}", DateTime.Now, MessageTypeToString(messageType), message);
        }

        bool LogMessageToWindow(string message, MessageType messageType)
        {
            if (_logWindowControl != null)
            {
                string msg = FormatMessage(message, messageType) + System.Environment.NewLine;
                _logWindowControl.LogRawMessage(msg);
                return true;
            }
            return false;
        }

        void LogMessageToFile(string message, MessageType messageType)
        {
            System.IO.StreamWriter sw = System.IO.File.AppendText(_logFileName);
            try
            {
                sw.WriteLine(FormatMessage(message, messageType));
            }
            finally
            {
                sw.Close();
            }
        }
        string _logFileName;
        private WindowManager _WindowManager;

        void CreateLogFile()
        {
            try
            {
                _logFileName = Path.Combine(_workingDirectory, "Addin.Log");
                LogMessage("Log File Created");
            }
            catch (Exception e)
            {
                LogError("Error CreateLogFile:" + e.Message);
            }
        }

        protected virtual string LogWindowName
        {
            get
            {
                return "ACSR Log";
            }
        }

        private void InitLogWindow()
        {
            try
            {
                _logWindow = this._WindowManager.FindOrCreateLogWindow(this.LogWindowName);
                _logWindowControl = ((dynamic)_logWindow.ControlObject);

                string assemblyName = Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                LogMessage(string.Format("Controller Loaded:{0} - {1}", _workingDirectory, assemblyName));

            }
            catch (Exception e)
            {
                LogError("Error InitLogWindoww: " + e.Message);
            }
        }
        //  object _objectExplorer = null;

        protected virtual void InternalOnConnectionCompleted()
        {
        }

        public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            try
            {
                CreateLogFile();

                InitLogWindow();
                InternalOnConnectionCompleted();

                LogMessage("Controller Connected");
            }
            catch (Exception e)
            {
                LogError("Error AddInController.OnConnection: " + e.Message);
            }
        }


        protected virtual void InternalOnDisconnectionCompleted(ext_DisconnectMode disconnectMode, ref Array custom)
        {

        }

        public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
        {
            this.InternalOnDisconnectionCompleted(disconnectMode, ref custom);

        }

        protected virtual void InternalOnAddInsUpdateCompleted(ref Array custom)
        {

        }

        public void OnAddInsUpdate(ref Array custom)
        {
            this.InternalOnAddInsUpdateCompleted(ref custom);
        }

        protected virtual void InternalOnStartupCompleteCompleted(ref Array custom)
        {

        }

        public void OnStartupComplete(ref Array custom)
        {
            try
            {
                _logWindow.Window.Visible = true;
            }
            catch (Exception e)
            {
                LogError("Error OnStartupComplete: " + e.Message);
            }
            this.InternalOnStartupCompleteCompleted(ref custom);

        }

        protected virtual void InternalOnBeginShutdownCompleted(ref Array custom)
        {

        }

        public void OnBeginShutdown(ref Array custom)
        {
            this.InternalOnBeginShutdownCompleted(ref custom);


        }

        protected virtual void InternalExec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled)
        {

        }

        public void Exec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled)
        {
            this.InternalExec(CmdName, ExecuteOption, ref VariantIn, ref VariantOut, ref Handled);


        }

        protected virtual void InternalQueryStatus(string CmdName, vsCommandStatusTextWanted NeededText, ref vsCommandStatus StatusOption, ref object CommandText)
        {

        }

        public void QueryStatus(string CmdName, vsCommandStatusTextWanted NeededText, ref vsCommandStatus StatusOption, ref object CommandText)
        {

            if (NeededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
            {
                this.InternalQueryStatus(CmdName, NeededText, ref StatusOption, ref CommandText);
            }
            StatusOption = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
            //CommandText = "TestCommandText";

        }

        #region IAddInController Members


        public dynamic GetCommand(string name)
        {
            dynamic command = null;
            if (this._commands.TryGetValue(name, out command))
            {
                return command;
            }

            throw new KeyNotFoundException(string.Format("The command was not found: {0}", name));
        }

        #endregion
    }

    public class ToolWindowContext : IToolWindowContext
    {
        public Window Window { get; set; }
        public Window Window2 { get; set; }
        public dynamic ControlObject { get; set; }
        public ToolWindowContext(Window Window, Window2 Window2, dynamic ControlObject)
        {
            this.Window = Window;
            this.Window2 = Window2;
            this.ControlObject = ControlObject;
        }
    }


}
